#include "ym_logger.h"
#include "ym_logger_def.h"
#include <cstring>
#include <iostream>
#include <chrono>


namespace Ymsf {
	namespace Infras {

		const std::string YMLogger::s_Level[LEVLE_COUNT] = { "DEBUG","INFO","WARN","ERROR","FATAL" };

		YMLogger* YMLogger::Instance()
		{
			static YMLogger instance;
			return &instance;
		}

		YMLogger::YMLogger():m_sFileName(LOGFILENAME),m_Size(0),m_Max(1024),m_Level(INFO)
		{
		}

		YMLogger::~YMLogger()
		{
		}
		void YMLogger::rotate()
		{
			Close();
			auto now = std::chrono::system_clock::now();
			std::time_t t = std::chrono::system_clock::to_time_t(now);
			std::tm* now_tm = std::localtime(&t);

			char timestamp[32];
			memset(timestamp, 0, sizeof(timestamp));
			std::strftime(timestamp, sizeof(timestamp), ".%Y-%m-%d_%H:%M:%S", now_tm);
			std::string filename = m_sFileName + timestamp;
			if (std::rename(m_sFileName.c_str(), filename.c_str())!=0)
			{
				throw std::logic_error("rename log file failed: " + std::string(strerror(errno)));
			}
			Open();
		}

		void YMLogger::Logger(Level level, std::string file, int line, std::string format)
		{
			Open();

			if (m_Fout.fail())
			{
				throw std::logic_error("open file error");
			}

			if (level < m_Level)
			{
				return; 
			}
			file = strrchr(file.c_str(), '\\') ? strrchr(file.c_str(), '\\') + 1 : file;
			
			auto now = std::chrono::system_clock::now();
			std::time_t t = std::chrono::system_clock::to_time_t(now); 
			std::tm* now_tm = std::localtime(&t);

			char timestamp[32];
			memset(timestamp, 0, sizeof(timestamp));
			std::strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", now_tm);

			std::string ftm = s_Level[level] + " " + file + " " + std::to_string(line) + " " + format + " " + timestamp;
			ftm += "\n";
			m_Fout << ftm;
			m_Size += ftm.size();
			m_Fout.flush();

			Close();

			//if (m_Size >= m_Max && m_Max >0)
			//{
			//	rotate();
			//}

		}


		void YMLogger::Open()
		{
			m_Fout.open(m_sFileName, std::ios::app);
			if (m_Fout.fail())
			{
				throw std::logic_error("open file failed" + m_sFileName);
			}
			m_Fout.seekp(0, std::ios::end);
			m_Size = m_Fout.tellp();
		}


		void YMLogger::Close()
		{
			m_Fout.close();
		}
		void YMLogger::SetLevel(Level lLevel)
		{
			m_Level = lLevel;
		}
		void YMLogger::SetMax(int iMax)
		{
			m_Max = iMax;
		}
	}
}
